package eval.deploy;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import eval.host.Host;
import eval.utilities.configuration.ExperimentConfiguration;
import eval.vm.VirtualMachine;

/**
 * This class manages the generation of the deploy track (i.e. which VM deploy
 * at each simulation cycle)
 * 
 * @author Nicolo' M. Calcavecchia <calcavecchia@elet.polimi.it>
 * @author Amit Peled   <amit.kapina@gmail.com>
 * @author Igal Kaufman <igal.kaufman@gmail.com>
 * 
 * */
@Singleton
public class DeployManager implements IDeployManager {

	private static ExperimentConfiguration configuration = ExperimentConfiguration.getSingleton();

	private double estimaitedAverageLifeTime = 0;
	private int totalNumberOfRemovedVMs = 0;
	private int sumOfVMsLifeTime = 0;

	private static final long serialVersionUID = 1L;

	private DeploySet deployRequests[];

	/**
	 * @Constructor
	 */
	@Inject
	public DeployManager() {
		deployRequests = new DeploySet[configuration.experimentTicks];
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#getDeploySetAtTick(int)
	 */
	@Override
	public DeploySet getDeploySetAtTick(int tick) {
		if (tick > configuration.experimentTicks)
			throw new IllegalArgumentException(
					"Trying to retrieve the deploy set for a non-existing cycle");

		if (deployRequests[tick] == null)
			return new DeploySet();

		return deployRequests[tick];

	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#getVMToBeRemovedAtTick(int, java.util.Map)
	 */
	@Override
	public List<VirtualMachine> getVMToBeRemovedAtTick(int cycle, Map<Host, List<VirtualMachine>> vmMapping) {
		List<VirtualMachine> vmToRemove = new ArrayList<VirtualMachine>();

		for(List<VirtualMachine> dsAtCicle : vmMapping.values()){

			for (VirtualMachine vm : dsAtCicle )
			{
				if(isVMRemovedAtTick(vm,cycle)){
					totalNumberOfRemovedVMs++;
					sumOfVMsLifeTime += cycle - vm.getStartLife();
					estimaitedAverageLifeTime = sumOfVMsLifeTime / totalNumberOfRemovedVMs;
					vmToRemove.add(vm);
				}
			}
		}
		return vmToRemove;
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#getVMToBeRemovedAtTick(int, java.util.List)
	 */
	@Override
	public List<VirtualMachine> getVMToBeRemovedAtTick(int cycle, List<VirtualMachine> vmList) {
		List<VirtualMachine> vmToRemove = new ArrayList<VirtualMachine>(); 
		for(VirtualMachine vm : vmList ){
			if(isVMRemovedAtTick(vm,cycle))
				vmToRemove.add(vm);
		}
		return vmToRemove;
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#isVMRemovedAtTick(eval.vm.VirtualMachine, int)
	 */
	@Override
	public boolean isVMRemovedAtTick(VirtualMachine virtualMachine, int cycle) {
		if((cycle - virtualMachine.getStartLife()) >= virtualMachine.getLifeTime())
			return true;
		return false;
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#setDeploySetAtTick(eval.deploy.DeploySet, int)
	 */
	@Override
	public void setDeploySetAtTick(DeploySet ds, int tick) {
		deployRequests[tick] = ds;
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#setVmStartLife(eval.vm.VirtualMachine, int)
	 */
	public void setVmStartLife(VirtualMachine vm,int cycle) {
		vm.setStartLifeAtTick(cycle);
	}

	/* (non-Javadoc)
	 * @see eval.deploy.IDeployManager#getEstimatedAverageLifeTime()
	 */
	@Override
	public double getEstimatedAverageLifeTime(){
		return Math.round(estimaitedAverageLifeTime);
	}
}
